package com.ddwl.wallet.service;

import com.ddwl.common.constant.BaseEnum;
import com.ddwl.common.constant.DistConstant;
import com.ddwl.common.constant.DistTypeEnum;
import com.ddwl.common.constant.GoodsEnum;
import com.ddwl.common.exception.ParamException;
import com.ddwl.common.exception.PayException;
import com.ddwl.schema.vo.order.OrderSpuVo;
import com.ddwl.wallet.dao.DistOrderInfoDao;
import com.ddwl.wallet.dao.OrderDao;
import com.ddwl.wallet.dao.SysOrderRefundDao;
import com.ddwl.wallet.dao.model.DistOrder;
import com.ddwl.wallet.dao.model.DistOrderInfo;
import com.ddwl.wallet.dao.model.SysOrderRefund;
import com.ddwl.wallet.service.dto.UserWalletChangeDto;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;

@Service
public class OrderRefundService {


    @Resource
    private SysOrderRefundDao sysOrderRefundDao;
    @Resource
    private OrderDao orderDao;
    @Resource
    private DistOrderInfoDao distOrderInfoDao;
    @Resource
    private UserWalletService userWalletService;


    /**
     * 提交退款接口
     * 提交退款申请时调用
     * 步骤1.创建分销退款订单
     * 步骤2。对分销订单进行标记售后，退款次数的叠加
     * @param orderId
     * @param spuId
     * @param refundAmount
     * @param refundId
     */
    public SysOrderRefund createOrderRefundAmount(String orderId, String spuId, BigDecimal refundAmount, String refundId,Integer skuQty) {
        SysOrderRefund refund = sysOrderRefundDao.selectOrderRefund(refundId);
        if(refund!=null){
            return refund;
        }
        DistOrderInfo orderInfo = distOrderInfoDao.queryDistOrderByOrderId(orderId);
        ParamException.isNull(orderInfo,"分销单不存在");
        refund = createSysOrderRefund(orderId,spuId,refundAmount,refundId,skuQty);
        refund.setShopId(orderInfo.getShopId());
        sysOrderRefundDao.insert(refund);
        //普通佣金标记为售后
        orderDao.addNumberRefund(orderId,spuId);
        //订单新增售后次数
        distOrderInfoDao.addNumberRefund(orderId,refundAmount);
        return refund;
    }

    /**
     *   提交退款 锁定退款金额
     *   注意：在调用支付渠道退款前调用
     *   步骤1.判断是否生成退款单如果没有生成创建退款单
     *   步骤2.如果是店铺订单锁定店铺退款金额
     * @param orderId
     * @param spuId
     * @param refundAmount
     * @param refundId
     */
    public SysOrderRefund  submitOrderRefundAmount(String orderId, String spuId, BigDecimal refundAmount, String refundId,Integer skuQty){
        SysOrderRefund refund = sysOrderRefundDao.selectOrderRefund(refundId);
        if(refund ==null){
            refund = createOrderRefundAmount(orderId,spuId,refundAmount,refundId,skuQty);
        }
        ParamException.isTrue(BaseEnum.ApplyEnum.SUCCEED.getCode().equals(refund.getStatus())|| BaseEnum.ApplyEnum.FILL.getCode().equals(refund.getStatus()),"退款单状态不正确无法完成提交退款");
        //更新退款状态
        if(BaseEnum.ApplyEnum.CRE.getCode().equals(refund.getStatus())){
            SysOrderRefund update = new SysOrderRefund();
            update.setStatus(BaseEnum.ApplyEnum.PRE.getCode());
            update.setRefundAmount(refundAmount);
            update.setId(refund.getId());
            sysOrderRefundDao.updateByPrimaryKeySelective(update);
            lockRefundAmount(sysOrderRefundDao.selectByPrimaryKey(refund.getId()));
        }
        return refund;
    }

    /**
     * 取消退款
     * 注意:在取消或者关闭售后单的时候调用
     * 步骤1.对分销订单退款次数递减
     * 步骤2.如果是店铺订单释放佣金
     * 步骤3.更新订单退款状态
     * @param refundId
     */
    public SysOrderRefund cancelOrderRefundAmount(String refundId) {
        SysOrderRefund refund = sysOrderRefundDao.selectOrderRefund(refundId);
        ParamException.isNull(refund,"退款单不存在");
        ParamException.isTrue(BaseEnum.ApplyEnum.SUCCEED.getCode().equals(refund.getStatus())||BaseEnum.ApplyEnum.FILL.getCode().equals(refund.getStatus()),"退款单状态不正确无法完成取消退款");
        //扣除售后次数
        orderDao.minusNumberRefund(refund.getOrderId(),refund.getOrderSpuId());
        distOrderInfoDao.minusNumberRefund(refund.getOrderId(),refund.getRefundAmount());
        //已经提交的售后单进行释放佣金释放佣金
        if(BaseEnum.ApplyEnum.PRE.getCode().equals(refund.getStatus())){
            releaseRefundAmount(refund);
        }
        refund.setStatus(BaseEnum.ApplyEnum.FILL.getCode());
        sysOrderRefundDao.updateByPrimaryKeySelective(refund);
        return refund;
    }

    /**
     * 完成退款接口
     * 更新退款订单状态
     * @param refundId
     */
    public SysOrderRefund completeOrderRefundAmount(String refundId) {
        SysOrderRefund refund = sysOrderRefundDao.selectOrderRefund(refundId);
        ParamException.isTrue(BaseEnum.ApplyEnum.SUCCEED.getCode().equals(refund.getStatus())||BaseEnum.ApplyEnum.FILL.getCode().equals(refund.getStatus()),"退款单状态不正确无法完成退款");
        ParamException.isNull(refund,"退款单不存在");
        refund.setStatus(BaseEnum.ApplyEnum.SUCCEED.getCode());
        sysOrderRefundDao.updateByPrimaryKeySelective(refund);
        return refund;
    }




    /**
     * 锁定退款金额
     * 步骤1：未结算分销佣金锁定给商家（注意如果订单结算了佣金退还至现金账号，如果是未结算退还至未结算订单）
     * 步骤2：锁定商家的退款金额（注意如果订单结算了扣除现金账号，如果是未结算扣除未结算订单）
     *
     * @param refund
     */
    private void lockRefundAmount(SysOrderRefund refund){
        ParamException.isFalse(BaseEnum.ApplyEnum.PRE.getCode().equals(refund.getStatus()),"订单状态不是未提交状态不能锁定佣金");
        DistOrderInfo orderInfo = distOrderInfoDao.queryDistOrderByOrderId(refund.getOrderId());
        ParamException.isNull(orderInfo,"该订单没有分销单，锁定资金失败");
        //只有店铺订单才需要锁定订单
        if (StringUtils.hasText(orderInfo.getShopId()) && GoodsEnum.CategoryTypeEnum.RETAIL.getCode().equals(orderInfo.getPlatformTag())) {
            List<DistOrder> distOrders = orderDao.queryDistOrder(refund.getOrderId(), refund.getOrderSpuId());
            DistOrder shopDist = orderDao.queryDistOrder(refund.getOrderId(), null, DistTypeEnum.SHOP.getType());
            ParamException.isNull(shopDist, "该订单没有店铺分销单，锁定资金失败");
            //本次退款的佣金
            BigDecimal firstRefund = distOrders.stream()
                    .filter(distOrder -> !DistConstant.DistOrderStatus.CLOSE.getCode().equals(distOrder.getOrderStatus()))
                    .filter(distOrder -> !DistTypeEnum.SHOP.getType().equals(distOrder.getDistType()))
                    .filter(distOrder -> distOrder.getNumberRefund() == 1)
                    .map(DistOrder::getDistAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
            //按数量退佣金
            //List<OrderSpuVo> spus= JSON.parseArray(orderInfo.getOrderSpu(), OrderSpuVo.class);
            //OrderSpuVo spuVo= spus.stream().filter(o->o.getId().equals(refund.getOrderSpuId())).findFirst().orElse(null);
            //firstRefund.multiply(BigDecimal.valueOf(refund.getSkuQty()).divide(BigDecimal.valueOf(spuVo.getSkuQty())));
            //校验退款总金额
            //checkAmount(refund,spuVo);
            //如果订单已结算锁定现金
            if (DistConstant.DistOrderStatus.CLOSE.getCode().equals(shopDist.getOrderStatus())) {
                //返回首次退款的佣金
                if (firstRefund.compareTo(BigDecimal.ZERO) > 0) {
                    userWalletService.userWalletChange(UserWalletChangeDto.buildUserWalletChangeDto(refund.getRefundId(), shopDist.getDistUserId(), DistConstant.WalletFlowType.SHOP_DIST_REFUND, firstRefund));
                }
                //扣除现金
                userWalletService.userWalletChange(UserWalletChangeDto.buildUserWalletChangeDto(refund.getRefundId(), shopDist.getDistUserId(), DistConstant.WalletFlowType.REFUND, refund.getRefundAmount()));
            } else {
                //未结算的直接更新佣金,返还首次退款的佣金
                shopDist.setDistAmount(shopDist.getDistAmount().add(firstRefund));
                shopDist.setTradeAmount(shopDist.getTradeAmount().subtract(firstRefund));
                if (shopDist.getDistAmount().compareTo(refund.getRefundAmount()) < 0) {
                    throw new PayException("商户金额不足锁定退款失败");
                }
                shopDist.setDistAmount(shopDist.getDistAmount().subtract(refund.getRefundAmount()));
                orderDao.updateByPrimaryKeySelective(shopDist);
            }
        }
    }

    private void checkAmount(SysOrderRefund refund,OrderSpuVo spuVo) {
        SysOrderRefund orderRefund=new SysOrderRefund();
        orderRefund.setOrderSpuId(refund.getOrderSpuId());
        List<SysOrderRefund> refunds = sysOrderRefundDao.select(orderRefund);
        ParamException.isTrue((refunds.stream()
                .filter(o->o.getStatus().equals(20)||o.getStatus().equals(10))
                .mapToInt(SysOrderRefund::getSkuQty).sum())
                +(refund.getSkuQty()==null?0:refund.getSkuQty())>spuVo.getSkuQty(),"退货数量不能大于实际购买数量");
        ParamException.isTrue((refunds.stream().filter(o->o.getStatus().equals(20)||o.getStatus().equals(10))
                .map(o-> o.getRefundAmount())
                .reduce(BigDecimal.ZERO,BigDecimal::add))
                .add(refund.getRefundAmount()).compareTo(spuVo.getRealPrice().multiply(new BigDecimal(spuVo.getSkuQty())))>0,"退款金额不能大于实际付款金额");
    }

    /**
     * 释放退款金额
     * 步骤1：退还商家订单未结算的分销佣金（注意如果订单结算了佣金退变更现金账号，如果是未结算变更未结算订单）
     * 步骤2：释放店铺的退款金额（注意如果订单结算了变更现金账号，如果是未结算变更结算订单）
     *
     * @param refund
     */
    private void releaseRefundAmount(SysOrderRefund refund){
        DistOrderInfo orderInfo = distOrderInfoDao.queryDistOrderByOrderId(refund.getOrderId());
        ParamException.isNull(orderInfo,"该订单没有分销单，释放锁定佣金失败");
        //只有店铺订单才需要释放金额
        if(!StringUtils.hasText(orderInfo.getShopId())||orderInfo.getPlatformTag()!=1) {
            return;
        }
        List<DistOrder> distOrders = orderDao.queryDistOrder(refund.getOrderId(), refund.getOrderSpuId());
        DistOrder shopDist = orderDao.queryDistOrder(refund.getOrderId(), null,DistTypeEnum.SHOP.getType());
        ParamException.isNull(shopDist,"该订单没有店铺分销单，释放锁定佣金失败");
        //本次退款的佣金
        BigDecimal firstRefund = distOrders.stream()
                .filter(distOrder-> !DistConstant.DistOrderStatus.CLOSE.getCode().equals(distOrder.getOrderStatus()))
                .filter(distOrder -> !DistTypeEnum.SHOP.getType().equals(distOrder.getDistType()))
                .filter(distOrder -> distOrder.getNumberRefund()==0)
                .map(DistOrder::getDistAmount)
                .reduce(BigDecimal.ZERO,BigDecimal::add);

        //按数量退佣金
        //List<OrderSpuVo> spus= JSON.parseArray(orderInfo.getOrderSpu(), OrderSpuVo.class);
        //OrderSpuVo spuVo= spus.stream().filter(o->o.getId().equals(refund.getOrderSpuId())).findFirst().orElse(null);
        //firstRefund.multiply(BigDecimal.valueOf(refund.getSkuQty()).divide(BigDecimal.valueOf(spuVo.getSkuQty())));
        //如果订单已结算释放锁定现金
        if(DistConstant.DistOrderStatus.CLOSE.getCode().equals(shopDist.getOrderStatus())){
            //归还佣金
            //返回首次退款的佣金
            if(firstRefund.compareTo(BigDecimal.ZERO)>0) {
                userWalletService.userWalletChange(UserWalletChangeDto.buildUserWalletChangeDto(refund.getRefundId(), shopDist.getDistUserId(), DistConstant.WalletFlowType.SHOP_DIST_REFUND_FALL, firstRefund));
            }
            //返回扣除现金
            userWalletService.userWalletChange(UserWalletChangeDto.buildUserWalletChangeDto(refund.getRefundId(), shopDist.getDistUserId(),DistConstant.WalletFlowType.REFUND_FALL,refund.getRefundAmount()));
        }else {
            //如果没有结算释放扣除佣金
            shopDist.setDistAmount(shopDist.getDistAmount().subtract(firstRefund));
            shopDist.setTradeAmount(shopDist.getTradeAmount().add(firstRefund));
            shopDist.setDistAmount(shopDist.getDistAmount().add(refund.getRefundAmount()));
            orderDao.updateByPrimaryKeySelective(shopDist);
        }

    }


    private SysOrderRefund createSysOrderRefund(String orderId, String spuId, BigDecimal refundAmount, String refundId,Integer skuQty){
        SysOrderRefund refund = new SysOrderRefund();
        refund.setOrderId(orderId);
        refund.setOrderSpuId(spuId);
        refund.setRefundAmount(refundAmount);
        refund.setRefundId(refundId);
        refund.setRefundCash(BigDecimal.ZERO);
        refund.setRefundCommission(BigDecimal.ZERO);
        refund.setStatus(BaseEnum.ApplyEnum.CRE.getCode());
        refund.setSkuQty(skuQty);
        return refund;
    }




}